/**
 ** 数据缓冲区
 ** 当前存储空间尺寸: 1024 * 32 bits
**/

module dataMemory (
    input wire clk,                         //时钟信号
    input wire rst,                         //复位信号
    input wire read_en,
    input wire write_en,
    input [2:0] dm_rd_ctrl,                 //数据读取控制信号
    input [1:0] dm_wr_ctrl,                 //数据写入控制信号
    input [31:0] dm_addr,                   //读or写地址
    input [31:0] dm_din,                    //待写入的内容
    input wire [4:0] save_no_in,            //保留站号输入
    input wire [4:0] rd_rob_in,             //结果影响到的ROB输入
    output reg done,
    output reg [4:0] save_no_out,           //保留站号输出
    output reg [4:0] rd_rob_out,            //结果影响到的ROB输出
    output reg [31:0] dm_dout               //存储器的输出
);
    //定义数组模拟存储器
    reg [3:0] byte_en;
    reg [31:0] mem[0:1023];
    reg [31:0] mem_out;
    reg [31:0] rd_addr;
    integer i;

    initial begin
        done = 0;
        //初始化存储单元
        for (i = 0; i < 1024; i++) begin
            mem[i] = 0;
        end
    end

    //读取逻辑
    always @(*) begin
        if (read_en) begin
            //如果是读取的话，将地址左移两位
            rd_addr = dm_addr;
            rd_addr = rd_addr << 2;
            $display("Read Addr: ", rd_addr);
            case (rd_addr[1:0])
                2'b00: mem_out = mem[rd_addr[13:2]][31:0];
                2'b01: mem_out = {8'h0,mem[rd_addr[13:2]][31:8]};
                2'b10: mem_out = {16'h0,mem[rd_addr[13:2]][31:16]};
                2'b11: mem_out = {24'h0,mem[rd_addr[13:2]][31:24]};
            endcase

            case(dm_rd_ctrl)     
                3'b001: dm_dout = {{24{mem_out[7]}}, mem_out[7:0]}; 
                3'b010: dm_dout = {{24{1'b0}}, mem_out[7:0]}; 
                3'b011: dm_dout = {{16{mem_out[15]}}, mem_out[15:0]}; 
                3'b100: dm_dout = {{16{1'b0}}, mem_out[15:0]}; 
                3'b101: dm_dout = mem_out[31:0];
                default: dm_dout = 0;
            endcase
        end

        done = read_en;
        rd_rob_out = rd_rob_in;
        save_no_out = save_no_in;
    end

    //写入逻辑
    always @(*) begin
        if (write_en) begin
            if(dm_wr_ctrl == 2'b11)
                byte_en = 4'b1111;
            else if(dm_wr_ctrl == 2'b10) begin
                if(dm_addr[1] == 1'b1) 
                    byte_en = 4'b1100;
                else
                    byte_en = 4'b0011;
            end
            else if(dm_wr_ctrl == 2'b01) begin
                case(dm_addr[1:0])
                2'b00:  byte_en = 4'b0001;
                2'b01:  byte_en = 4'b0010;
                2'b10:  byte_en = 4'b0100;
                2'b11:  byte_en = 4'b1000;
                endcase
            end
            else
                byte_en = 4'b0000;

            if((byte_en != 1'b0)&&(dm_addr[30:12]==19'b0)) begin
                case(byte_en)
                    4'b0001: mem[dm_addr[13:2]][7:0] = dm_din[7:0]; //单字节写入
                    4'b0010: mem[dm_addr[13:2]][15:8] = dm_din[7:0]; //单字节写入
                    4'b0100: mem[dm_addr[13:2]][23:16] = dm_din[7:0]; //单字节写入
                    4'b1000: mem[dm_addr[13:2]][31:24] = dm_din[7:0]; //单字节写入
                    4'b0011: mem[dm_addr[13:2]][15:0] = dm_din[15:0]; //半字写入
                    4'b1100: mem[dm_addr[13:2]][31:16] = dm_din[15:0]; //半字写入
                    4'b1111: mem[dm_addr[13:2]] = dm_din[31:0]; //整字写入 
                    default: mem[dm_addr[13:2]] = 0;
                endcase
            end
            //$display("The word: ",dm_din," addr is: ",dm_addr);
        end
    end
endmodule